#include "StdAfx.h"
#include "DrawFrame.h"
#include "D3D9.h"

CDrawFrame::CDrawFrame()
{
	m_pDevice = NULL;
	m_pSwapChain = NULL;

	m_nSwapChainWidth = 0;
	m_nSwapChainHeight = 0;
}

CDrawFrame::~CDrawFrame(void)
{
	CloseDevice();
}

void CDrawFrame::OpenDevice(HWND hWnd)
{
	CloseDevice();
	CreateDevice(hWnd);

	m_hWnd = hWnd;
}

HRESULT CDrawFrame::CreateDevice(HWND hwnd)
{
	IDirect3D9* pD3D;
	pD3D = Direct3DCreate9(D3D_SDK_VERSION);

	HRESULT hr = S_OK;
    D3DPRESENT_PARAMETERS pp = { 0 };
    D3DDISPLAYMODE mode = { 0 };

    hr = pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode);
	hr = pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format, D3DFMT_X8R8G8B8, TRUE);

	pp.BackBufferFormat = D3DFMT_X8R8G8B8;
    pp.SwapEffect = D3DSWAPEFFECT_COPY;
    pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    pp.Windowed = TRUE;
    pp.hDeviceWindow = hwnd;

	hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &pp, &m_pDevice);

	return hr;
}

HRESULT CDrawFrame::CreateSwapChains(HWND hWnd, int nWidth, int nHeight)
{
	DestroySwapChain();

    HRESULT hr = S_OK;

    D3DPRESENT_PARAMETERS pp = { 0 };

    pp.BackBufferWidth  = nWidth;
    pp.BackBufferHeight = nHeight;
    pp.Windowed = TRUE;
    pp.SwapEffect = D3DSWAPEFFECT_FLIP;
    pp.hDeviceWindow = hWnd;
    pp.BackBufferFormat = D3DFMT_X8R8G8B8;
    pp.Flags = D3DPRESENTFLAG_VIDEO | D3DPRESENTFLAG_DEVICECLIP | D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    pp.BackBufferCount = D3DPRESENT_BACK_BUFFERS_MAX;

    hr = m_pDevice->CreateAdditionalSwapChain(&pp, &m_pSwapChain);

    return hr;
}

HRESULT CDrawFrame::PostData(int nWidth, int nHeight, BYTE* DataForDisplay)
{
	if (m_pDevice == NULL)
		return S_OK;
    
	HRESULT hr = S_OK;

	D3DLOCKED_RECT lr;
	IDirect3DSurface9 *pSurf = NULL;
    IDirect3DSurface9 *pBB = NULL;

	if(m_nSwapChainWidth != nWidth || m_nSwapChainHeight != nHeight)
	{
		CreateSwapChains(m_hWnd, nWidth, nHeight);

		m_nSwapChainWidth = nWidth;
		m_nSwapChainHeight = nHeight;
	}

    if (m_pDevice == NULL || m_pSwapChain == NULL)
    {
        return hr;
    }

	hr = m_pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf);

	hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK );
	
	int nFrameLen = nWidth * nHeight * 4;
	
	int nSrcStride = nWidth * 4;
	int nDscStride = lr.Pitch;
			
	for(int nScanLine = 0, nScanSrc = 0, nScanDsc = 0; nScanLine < nHeight; nScanLine++, nScanSrc +=  nSrcStride, nScanDsc += nDscStride)
	{
		char* pDsc = (char*) lr.pBits;

		::memcpy(&pDsc[nScanDsc], &DataForDisplay[nScanSrc], nSrcStride);
	}

	hr = pSurf->UnlockRect();
		
    hr = m_pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB);
    hr = m_pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0, 0, 0x80));
    hr = m_pDevice->StretchRect(pSurf, NULL, pBB, NULL, D3DTEXF_LINEAR);

    hr = m_pDevice->Present(NULL, NULL, NULL, NULL);

	return hr;
}

void CDrawFrame::CloseDevice()
{
	DestroySwapChain();
	
	if(m_pDevice)
	{
		m_pDevice->Release();
		m_pDevice = NULL;
	}
}

void CDrawFrame::DestroySwapChain()
{
	if(m_pSwapChain)
	{
		m_pSwapChain->Release();
		m_pSwapChain = NULL;

		m_nSwapChainWidth = 0;
		m_nSwapChainHeight = 0;
	}
}

